package org.wevil.util;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Stream;

/**
 * 日期工具类
 *
 * @author wanglei
 * @since 2020/12/4
 */
public class DateUtil {

    /**
     * 日期格式
     * */
    final public static String DATE_FORMAT = "yyyy-MM-dd";

    /**
     * 日期时间格式
     * */
    final public static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    // ############################ 日期格式转换 #####################################//

    /**
     * 字符串转LocalDateTime
     *
     * @param str 日期字符串：2024-01-29 13:45:30
     * @param pattern 格式：yyyy-MM-dd HH:mm:ss
     * @author wanglei
     * @since 2024-01-29
     */
    public static LocalDateTime convertStr2LocalDatetime(String str, String pattern){
        // 定义与字符串匹配的日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        // 解析字符串为LocalDateTime对象
        return LocalDateTime.parse(str, formatter);
    }

    /**
     * 字符串转Timestamp，精确到秒
     *
     * @since 2022/4/27
     * */
    public static Timestamp convertStr2Timestamp(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
        Date parse;
        try {
            parse = sdf.parse(str);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return new Timestamp(parse.getTime());
    }

    /**
     * 字符串转Timestamp，精确到秒
     * @param format 字符串格式,例如：yyyy-MM-dd HH:mm:ss
     * */
    public static Timestamp convertStr2Timestamp(String str, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date parse;
        try {
            parse = sdf.parse(str);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return new Timestamp(parse.getTime());
    }

    /** Timestamp转字符串，精确到秒 */
    public static String convertTimestamp2Str(Timestamp time){
        if (null != time) {
            return new SimpleDateFormat(DATETIME_FORMAT).format(time);
        } else {
            return "";
        }
    }

    /** Timestamp转字符串，自定义格式。如：yyyy-MM-dd HH:mm:ss */
    public static String convertTimestamp2Str(Timestamp time, String format){
        if (null != time) {
            return new SimpleDateFormat(format).format(time);
        } else {
            return "";
        }
    }

    /**
     * 字符串转日期
     *
     * @param str 格式：yyyy-MM-dd
     */
    public static Date convertStr2Date(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        return sdf.parse(str);
    }

    /**
     * 字符串转日期时间
     *
     * @param str 格式：yyyy-MM-dd HH:mm:ss
     */
    public static Date convertStr2DateTime(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
        return sdf.parse(str);
    }

    /**
     * 字符串转日期
     *
     * @param format 日期格式。例如：yyyy-MM-dd HH:mm:ss
     * @author wanglei
     * @since 2021/6/25
     */
    public static Date convertStr2DateTime(String str, String format) throws ParseException {
        return DateUtils.parseDate(str, format);
    }

    /**
     * 日期转字符串。默认格式：yyyy-MM-dd
     */
    public static String convertDate2Str(Date date) {
        return DateFormatUtils.format(date, DATE_FORMAT);
    }

    /**
     * 日期转字符串
     *
     * @param format 日期格式。例如：yyyy-MM-dd HH:mm:ss
     * @author wanglei
     * @since 2021/6/25
     */
    public static String convertDate2Str(Date date, String format) {
        return DateFormatUtils.format(date, format);
    }

    /**
     * sql日期转字符串
     *
     * @return 格式：yyyy-MM-dd
     * @since 2022/4/6
     */
    public static String convertSqlDate2Str(java.sql.Date date) {
        return DateFormatUtils.format(date, DATE_FORMAT);
    }

    /**
     * 字符串转java.sql.Date日期
     *
     * @param str 格式：yyyy-MM-dd
     * @author wanglei
     * @since 2021/6/24
     */
    public static java.sql.Date convertStr2SqlDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        Date parse = sdf.parse(str);
        return new java.sql.Date(parse.getTime());
    }

    /**
     * 两个日期的时间差毫秒数->天时分秒毫秒明文
     *
     * @param ms 毫秒时间差
     * @return 转换好的时分秒字符串
     */
    public static String convertMs2Plain(Long ms) {
        Integer ss = 1000;
        Integer mi = ss * 60;
        Integer hh = mi * 60;
        Integer dd = hh * 24;

        Long day = ms / dd;
        Long hour = (ms - day * dd) / hh;
        Long minute = (ms - day * dd - hour * hh) / mi;
        Long second = (ms - day * dd - hour * hh - minute * mi) / ss;
        long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;

        StringBuffer sb = new StringBuffer();
        if (day > 0) {
            sb.append(day).append("天");
        }
        if (hour > 0) {
            sb.append(hour).append("小时");
        }
        if (minute > 0) {
            sb.append(minute).append("分");
        }
        if (second > 0) {
            sb.append(second).append("秒");
        }
        if (milliSecond > 0) {
            sb.append(milliSecond).append("毫秒");
        }
        return sb.toString();
    }

    /**
     * 毫秒转日期 yyyy-MM-dd HH:mm:ss
     * */
    public static String convertMs2Time(Long ms){
        // 创建SimpleDateFormat，指定目标格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 可选：设置时区（避免默认时区影响，例如UTC）
        sdf.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));
        // 将毫秒转为Date，再格式化字符串
        return sdf.format(new Date(ms));
    }

    // ############################ 时间计算 #####################################//

    /**
     * 根据开始日期和结束日期(Date类型)获取中间所有天数的字符串列表
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 包含所有日期的列表
     */
    public static List<String> getDatesBetween(Date startDate, Date endDate) {
        // 定义日期格式
        SimpleDateFormat FORMATTER = new SimpleDateFormat(DATE_FORMAT);
        List<String> dateList = new ArrayList<>();
        // 确保开始日期和结束日期不为空
        if (startDate == null || endDate == null) {
            return dateList;
        }
        // 确保开始日期不晚于结束日期
        if (startDate.after(endDate)) {
            return dateList;
        }
        // 使用Calendar进行日期递增
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        // 循环添加日期直到超过结束日期
        while (!calendar.getTime().after(endDate)) {
            dateList.add(FORMATTER.format(calendar.getTime()));
            calendar.add(Calendar.DATE, 1);
        }
        return dateList;
    }

    /**
     * 获取最近几个月的月日字符串列表
     * @param day 最近几日，最近3天就输入3
     * @return [12-01, 12-02, 12-03]
     * */
    public static List<String> getLastMd(Integer day){
        List<String> mdList = new ArrayList<>();
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 计算几个月前的第一天
        LocalDate lastMonthDay = today.minusDays(day-1);
        // 格式化输出器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
        // 创建一个日期间隔
        Iterable<LocalDate> datesInRange = () -> Stream.iterate(lastMonthDay, date -> date.plusDays(1))
                .limit(day)
                .iterator();
        // 遍历这个区间并打印每个日期的年月
        for (LocalDate date : datesInRange) {
            mdList.add(date.format(formatter));
        }
        return mdList;
    }

    /**
     * 获取最近几个月的年月字符串列表
     * @param month 最近几个月，最近3个月就输入3
     * @return [2023-12, 2024-01, 2024-02]
     * */
    public static List<String> getLastYm(Integer month){
        List<String> ymList = new ArrayList<>();
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 计算几个月前的第一天
        LocalDate lastMonthDay = today.minusMonths(month-1);
        // 格式化输出器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        // 创建一个日期间隔
        Iterable<LocalDate> datesInRange = () -> Stream.iterate(lastMonthDay, date -> date.plusMonths(1))
                .limit(month)
                .iterator();
        // 遍历这个区间并打印每个日期的年月
        for (LocalDate date : datesInRange) {
            ymList.add(date.format(formatter));
        }
        return ymList;
    }

    /**
     * 获取当前时间字符串
     *
     * @return 示例：2022-03-04 12:44:00
     * @since 2022/3/4
     */
    public static String getTimeStr() {
        SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前时间字符串
     *
     * @param format 日期格式，yyyy-MM-dd HH:mm:ss
     */
    public static String getTimeStr(String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前时间字符串，没有分隔符
     *
     * @return 示例：20220304124400
     */
    public static String getTimeStrNoSplit() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前日期字符串
     *
     * @return 示例：2022-03-04
     * @since 2022/3/4
     */
    public static String getDateStr() {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /** 获取当日日期字符串，自定义格式，例如：yyyy-MM-dd HH:mm:ss
     * */
    public static String getDateStr(String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前年份
     *
     * @author wanglei
     * @since 2021/6/24
     */
    public static Integer getYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR);
    }

    /**
     * 获取当前月份
     *
     * @author wanglei
     * @since 2021/6/24
     */
    public static Integer getMonth() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取当前月最后一天
     *
     * @author wanglei
     * @since 2023-12-08
     */
    public static Integer getLastDayOfMonth(){
        Calendar calendar = Calendar.getInstance();
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当前月的第一天和最后一天的时间
     * 示例：[2023-12-01 00:00:00, 2023-12-31 23:59:59]
     *
     * @author wanglei
     * @since 2023-12-08
     */
    public static String[] getStartAndLastDay(){
        Calendar cal = Calendar.getInstance();
        String year = cal.get(Calendar.YEAR)+"";
        String month = NumberUtil.addZeroForNum((cal.get(Calendar.MONTH) + 1) + "", 2);
        String lastDayOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH)+""; // 当前月最后一天

        String startTime = String.format("%s-%s-01 00:00:00", year, month);
        String endTime = String.format("%s-%s-%s 23:59:59", year, month, lastDayOfMonth);

        return new String[]{startTime, endTime};
    }

    /**
     * 指定几号，获取上一个月几号，这个月的几号的日期。比如：上月26到本月25
     * 示例：[2023-11-26 00:00:00, 2023-12-25 23:59:59]
     *
     * @param dayOfMonth 几号，上月26到本月25，传26
     *
     * @author wanglei
     * @since 2023-12-22
     */
    public static String[] getStartAndLastDay(Integer dayOfMonth){
        Calendar cal_cur = Calendar.getInstance();
        // 获取当前几号
        int currentDay = cal_cur.get(Calendar.DAY_OF_MONTH);
        // 获取当前月份
        int currentMonth = cal_cur.get(Calendar.MONTH);
        // 如果是26号以后，则应该计算下个月
        if(currentDay>=dayOfMonth){
            currentMonth++;
        }

        cal_cur.set(Calendar.DAY_OF_MONTH, dayOfMonth-1);
        cal_cur.set(Calendar.MONTH, currentMonth);

        Calendar cal_last = Calendar.getInstance();
        cal_last.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        cal_last.set(Calendar.MONTH, currentMonth-1);

        SimpleDateFormat sdfStart = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        SimpleDateFormat sdfEnd = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
        Date time_last = cal_last.getTime();
        String startTime = sdfStart.format(time_last);
        Date time_cur = cal_cur.getTime();
        String endTime = sdfEnd.format(time_cur);

        return new String[]{startTime, endTime};
    }

    /**
     * 获取当前月的第一天和最后一天的时间，LocalDateTime格式
     * 示例：[2023-12-01 00:00:00, 2023-12-31 23:59:59]
     *
     * @author wanglei
     * @since 2023-12-08
     */
    public static LocalDateTime[] getStartAndLastDayLdt(){
        Calendar cal = Calendar.getInstance();
        String year = cal.get(Calendar.YEAR)+"";
        String month = NumberUtil.addZeroForNum((cal.get(Calendar.MONTH) + 1) + "", 2);
        String lastDayOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH)+""; // 当前月最后一天

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_FORMAT);
        String startTimeStr = String.format("%s-%s-01 00:00:00", year, month);
        LocalDateTime startTime = LocalDateTime.parse(startTimeStr, formatter);
        String endTimeStr = String.format("%s-%s-%s 23:59:59", year, month, lastDayOfMonth);
        LocalDateTime endTime = LocalDateTime.parse(endTimeStr, formatter);

        return new LocalDateTime[]{startTime, endTime};
    }

    /**
     * 指定几号，获取上一个月几号，这个月的几号的日期。比如：上月26到本月25
     * 示例：[2023-11-26 00:00:00, 2023-12-25 23:59:59]
     *
     * @param dayOfMonth 几号，上月26到本月25，传26
     *
     * @author wanglei
     * @since 2023-12-22
     */
    public static LocalDateTime[] getStartAndLastDayLdt(Integer dayOfMonth){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_FORMAT);
        String[] startAndLastDay = getStartAndLastDay(dayOfMonth);
        return new LocalDateTime[]{
                LocalDateTime.parse(startAndLastDay[0], formatter),
                LocalDateTime.parse(startAndLastDay[1], formatter)};
    }

    /**
     * 获取当前几号
     *
     * @author wanglei
     * @since 2021/6/24
     */
    public static Integer getDay() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取指定日期年份
     *
     * @author wanglei
     * @since 2021/9/2
     */
    public static Integer getYear(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.YEAR);
    }

    /**
     * 获取指定日期月份
     *
     * @author wanglei
     * @since 2021/9/2
     */
    public static Integer getMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.MONTH);
    }

    /**
     * 获取指定日期几号
     *
     * @author wanglei
     * @since 2021/9/2
     */
    public static Integer getDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当前sql时间
     *
     * @author wanglei
     * @since 2021/6/28
     */
    public static java.sql.Date getCurrentSqlDate() {
        Date date = new Date();
        return new java.sql.Date(date.getTime());
    }

    /**
     * 获取一个月有多少天
     *
     * @author wanglei
     * @since 2021/11/29
     */
    public static Integer getDays(Integer year, Integer month) {
        if (month == 2) {
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
                return 29;
            } else {
                return 28;
            }
        } else if (month == 4 || month == 6 || month == 9 || month == 11) {
            return 30;
        } else {
            return 31;
        }
    }

    // ############################ 计算指定日期前后多少天的时间 ##################################### //

    /**
     * 获取多少天前后的日期 java.sql.Date
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     */
    public static java.sql.Date calSqlDateBeforeAfter(java.sql.Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new java.sql.Date(time.getTime());
    }

    /**
     * 获取多少天前后的日期
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     * @author wanglei
     * @since 2021/8/30
     */
    public static Date calDateBeforeAfter(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new Date(time.getTime());
    }

    /**
     * 获取多少天前后的日期
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     * @author wanglei
     * @since 2021/8/30
     */
    public static Timestamp calTimestampBeforeAfter(Timestamp date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new Timestamp(time.getTime());
    }

    /**
     * 获取当前日期的月份第一天
     *
     * @author wanglei
     * @since 2021/6/4
     */
    public static Date calDateMonthFirstDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获取某月最小天数
        int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        return cal.getTime();
    }

    /**
     * 获取当前日期的月份第一天
     *
     * @author wanglei
     * @since 2021/6/4
     */
    public static String calDateMonthFirstDay(int year, int month) {
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最小天数
        int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        return sdf.format(cal.getTime()) + " 00:00:00";
    }

    /**
     * 获得该月最后一天
     *
     * @author wanglei
     * @since 2021/6/4
     */
    public static Date calDateMonthLastDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        return cal.getTime();
    }

    /**
     * 获得该月最后一天
     *
     * @author wanglei
     * @since 2021/6/4
     */
    public static String calDateMonthLastDay(int year, int month) {
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        return sdf.format(cal.getTime()) + " 23:59:59";
    }

    /**
     * 获取一个时间几个小时后的日期
     *
     * @author wanglei
     * @since 2021/6/25
     */
    public static Date getDateAfterHour(Date date, int hour) {
        return DateUtils.addHours(date, hour);
    }

    // ############################ 日期差 #####################################//

    /**
     * 获取两个日期相差的天数
     *
     * @author wanglei
     * @since 2021/5/12
     */
    public static long diffDaysByDate(Date start, Date end) {
        //打印控制台相差的天数
        return  (end.getTime() - start.getTime()) / (60 * 60 * 24 * 1000);
    }

    /**
     * 获取两个日期相差的天数
     */
    public static long diffDaysByLocalDateTime(LocalDateTime start, LocalDateTime end) {
        // 计算时间差
        Duration duration = Duration.between(start, end);
        return duration.toDays();
    }

    /**
     * 获取两个日期相差的天数
     */
    public static long diffDaysByTimestamp(Timestamp start, Timestamp end) {
        //打印控制台相差的天数
        return (end.getTime() - start.getTime()) / (60 * 60 * 24 * 1000);
    }

    /**
     * 获取连个日期之间相差的月份
     *
     * @param startDate 开始日期 格式：yyyy-MM
     * @param endDate   结束日期 格式：yyyy-MM
     * @author wanglei
     * @since 2021/6/4
     */
    public static Integer diffMonthsByStr(String startDate, String endDate) throws ParseException {
        List<String> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(sdf.parse(startDate));
        c2.setTime(sdf.parse(endDate));
        int year = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        int month = c2.get(Calendar.MONTH) + year * 12 - c1.get(Calendar.MONTH);
        for (int i = 0; i <= month; i++) {
            c1.setTime(sdf.parse(startDate));
            c1.add(Calendar.MONTH, i);
            list.add(sdf.format(c1.getTime()));
        }
        return list.size();
    }

    /**
     * 获取连个日期之间相差的月份
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @author wanglei
     * @since 2023-01-16
     */
    public static Integer diffMonthsByDate(Date startDate, Date endDate) {
        // 将Date转换为LocalDate
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        long totalMonths = ChronoUnit.MONTHS.between(start, end);
        long remainingDays = ChronoUnit.DAYS.between(start.plusMonths(totalMonths), end); // 计算跨越月份后剩余的天数
        if (remainingDays > 0) { // 如果有剩余天数，则增加一个月计数，并减少剩余天数
            totalMonths++;
        }
        return (int) totalMonths;
    }

    /**
     * 获取两个Timestamp的时间差多少秒
     *
     * @since 2022/4/27
     */
    public static int diffSecondsByTimestamp(Timestamp start, Timestamp end) {
        long t1 = start.getTime();
        long t2 = end.getTime();
        return (int) ((t2 - t1) / (1000));
    }

    /**
     * 获取两个Timestamp的时间差多少分钟
     *
     * @author wanglei
     * @since 2021/6/6
     */
    public static int diffMinutesByTimestamp(Timestamp time1, Timestamp time2) {
        long t1 = time1.getTime();
        long t2 = time2.getTime();
        return (int) ((t1 - t2) / (1000 * 60));
    }

    /**
     * 获取两个Timestamp的时间差多少小时
     *
     * @author wanglei
     * @since 2021/6/6
     */
    public static int diffHoursByTimestamp(Timestamp time1, Timestamp time2) {
        long t1 = time1.getTime();
        long t2 = time2.getTime();
        return (int) ((t1 - t2) / (1000 * 60 * 60));
    }

    /**
     * 获取两个Timestamp的时间差明文
     * return xx小时xx分xx秒
     */
    public static String diffPlainByTimestamp(Timestamp formatTime1, Timestamp formatTime2) {
        long t1 = formatTime1.getTime();
        long t2 = formatTime2.getTime();
        int hours = (int) ((t1 - t2) / (1000 * 60 * 60));
        int minutes = (int) (((t1 - t2) / 1000 - hours * (60 * 60)) / 60);
        int second = (int) ((t1 - t2) / 1000 - hours * (60 * 60) - minutes * 60);
        return hours + "小时" + minutes + "分" + second + "秒";
    }

    /**
     * 获取一个区间段的月份与日期数组
     *
     * @param startDate 起始日期
     * @param endDate   结束日期
     */
    public static String[] diffMonthDayArrayByDate(Date startDate, Date endDate) {
        String[] section;
        // 获取起始的月日
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        // 获取两个日期的间隔天数
        int betweenDate = Integer.parseInt(Long.toString((endDate.getTime() - startDate.getTime()) / (60 * 60 * 24 * 1000)));
        section = new String[betweenDate];
        for (int i = 0; i < betweenDate; i++) {
            int startDay = startCalendar.get(Calendar.DAY_OF_MONTH);
            int startMonth = startCalendar.get(Calendar.MONTH) + 1;
            section[i] = startMonth + "-" + startDay;
            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return section;
    }

    /**
     * 获取一个区间段的年-月-日
     *
     * @param startDate 起始日期
     * @param endDate   结束日期
     */
    public static String[] diffYearMonthDayArrayByDate(Date startDate, Date endDate) {
        String[] section;
        // 获取起始的月日
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        // 获取两个日期的间隔天数
        int betweenDate = Integer.parseInt(Long.toString((endDate.getTime() - startDate.getTime()) / (60 * 60 * 24 * 1000)));
        section = new String[betweenDate];
        for (int i = 0; i < betweenDate; i++) {
            int startYear = startCalendar.get(Calendar.YEAR);
            int startDay = startCalendar.get(Calendar.DAY_OF_MONTH);
            int startMonth = startCalendar.get(Calendar.MONTH) + 1;
            section[i] = startYear + "-" + startMonth + "-" + startDay;
            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return section;
    }

    // ############################ 日期判断 #####################################//

    /**
     * 字符串是否是年份的。比如2019是，11.23不是
     *
     * @param str 字符串
     * @return true：是年份，false：不是年份
     */
    public static boolean isYear(String str) {
        boolean convertSuccess = true;
        SimpleDateFormat format = new SimpleDateFormat("yyyy");
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 判断字符串是否是 yyyy/MM/dd HH:mm 格式
     *
     * @param str 字符串
     * @return true：是，false：不是
     */
    public static boolean isValidDate(String str) {
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写；
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 判断两个日期是否相同
     * */
    public static boolean isSameDate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }

        // 将Date转换为LocalDate（自动忽略时间部分）
        LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 直接比较LocalDate
        return localDate1.equals(localDate2);
    }

}
